package cn.jingyuan.swan.gw.web.security;

import cn.jingyuan.bee.exception.SystemException;
import cn.jingyuan.bee.fastjson.FastJsonUtils;
import cn.jingyuan.swan.cloud.core.Result;
import cn.jingyuan.swan.cloud.oauth2.error.DefaultOAuth2ExceptionSupport;
import cn.jingyuan.swan.cloud.web.AbstractExceptionHandler;
import cn.jingyuan.swan.gw.service.AccessLogService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.oauth2.common.DefaultThrowableAnalyzer;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.util.ThrowableAnalyzer;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;

/**
 * 访问拒绝
 */
@Slf4j
@Component
public class JsonAccessDeniedHandler implements AccessDeniedHandler {

    private final ThrowableAnalyzer throwableAnalyzer = new DefaultThrowableAnalyzer();

    @Resource
    private AccessLogService accessLogService;

    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException)
        throws IOException, ServletException {
        // Try to extract a SpringSecurityException from the stacktrace
        Throwable[] causeChain = throwableAnalyzer.determineCauseChain(accessDeniedException);
        Exception ase = (SystemException) throwableAnalyzer.getFirstThrowableOfType(SystemException.class, causeChain);

        if (null != ase) {
            accessLogService.sendLog(request, response, ase);

            SystemException sex = (SystemException) ase;

            Result rs = AbstractExceptionHandler.resolveEx(sex);

            response.setStatus(rs.getHttpStatus());
            response.setContentType(APPLICATION_JSON_VALUE);

            String body = FastJsonUtils.json(rs);

            PrintWriter writer = response.getWriter();
            writer.write(body);
            writer.flush();
        } else {
            // 优先获取 SystemException，若 SystemException 为空，则继续获取 OAuth2Exception
            if (null == ase) {
                ase = (OAuth2Exception) throwableAnalyzer.getFirstThrowableOfType(OAuth2Exception.class, causeChain);
            }

            if (null == ase) {
                ase = accessDeniedException;
            }

            accessLogService.sendLog(request, response, ase);

            DefaultOAuth2ExceptionSupport.doCommence(request, response, ase);
        }
    }

}
